package com.tonyodev.fetch2fileserver;

import ohos.app.Context;

import com.tonyodev.fetch2core.FileResource;
import com.tonyodev.fetch2core.Func;
import com.tonyodev.fetch2core.Func2;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.Collection;
import java.util.List;

import static com.tonyodev.fetch2core.FetchCoreDefaults.DEFAULT_PERSISTENT_TIME_OUT_IN_MILLISECONDS;
import static com.tonyodev.fetch2core.FetchCoreDefaults.DEFAULT_PROGRESS_REPORTING_INTERVAL_IN_MILLISECONDS;


/**
 * @since 2021-05-21
 */
public interface FetchFileServer {
    /**
     * File Server Unique id.
     *
     * @return 字符串
     */
    String getId();

    /**
     * getPort
     *
     * @return 1
     */
    int getPort();

    /**
     * The file server IP address. The IP address is available after the server has started.
     *
     * @return 1
     */
    String getAddress();

    /**
     * Indicates if the File Server is shutdown.
     *
     * @return q
     */
    boolean isShutDown();

    /**
     * Starts the file server. File Server beings to listen for requests on the designated port.
     */
    void start();

    /**
     * Shuts down the file server. The File server will no longer accept request or allow
     * file resources to be attached. Once called any method call to the instance will throw
     * an exception indicating that the instance is no longer available for use.
     *
     * @param forced forces the file server to cancel active requests that are being served to
     * any connected clients and terminates all operations and connections.
     */
    void shutDown(boolean forced);

    /**
     * Adds a FileResource that can be served to requesting clients.
     *
     * @param fileResource a file resource.
     */
    void addFileResource(FileResource fileResource);

    /**
     * Adds a list of FileResource that can be served to requesting clients.
     *
     * @param fileResources a list file resource.
     */
    void addFileResources(Collection<FileResource> fileResources);

    /**
     * Removes a fileResource from the instance of the File Server.
     *
     * @param fileResource file resource
     */
    void removeFileResource(FileResource fileResource);

    /**
     * Removes a list of FileResource from the File Server instance.
     *
     * @param fileResources a list file resource.
     */
    void removeFileResources(Collection<FileResource> fileResources);

    /**
     * Removes all FileResources managed by this instance.
     */
    void removeAllFileResources();

    /**
     * Checks if a File Resource is managed by this instance.
     *
     * @param fileResourceId file resource id
     * @param func callback the result will be returned on. True if the file resource
     * is being managed. False otherwise.
     */
    void containsFileResource(long fileResourceId, Func<Boolean> func);

    /**
     * Gets a list of all File Resources managed by this File Server instance.
     *
     * @param func callback the result is returned on.
     */
    void getFileResources(Func<List<FileResource>> func);

    /**
     * Gets the Catalog(All File Resources) managed by this File Server instances
     * as JSON. The FileResources `file` field is excluded.
     *
     * @param func callback the result will be returned on.
     */
    void getCatalog(Func<String> func);

    /**
     * Queries the File Server instance for a managed file resource if it exist.
     *
     * @param fileResourceId file resource id
     * @param func2 callback the result will be returned on. Result maybe null if it does not exist.
     */
    void getFileResource(long fileResourceId, Func2<FileResource> func2);

    /**
     * 目前有问题
     */
    public static final class Builder {
        private ServerSocket serverSocket = new ServerSocket(0);
        private boolean clearDatabaseOnShutdown = false;
        private FetchFileServerLogger logger = new FetchFileServerLogger();
        private FetchFileServerAuthenticator fileServerAuthenticator;
        private FetchFileServerDelegate fileServerDelegate;
        private FetchTransferListener transferListener;
        private String fileResourceDatabaseName = "LibFetchFileServerDatabaseLib.db";
        private long progressReportingInMillis = DEFAULT_PROGRESS_REPORTING_INTERVAL_IN_MILLISECONDS;
        private long persistentConnectionTimeout = DEFAULT_PERSISTENT_TIME_OUT_IN_MILLISECONDS;
        private FileResolver fileResolver;
        private final Context context;

        /**
         * Set Custom Server Socket
         *
         * @param serverSocket
         * @return builder
         */
        public final FetchFileServer.Builder setServerSocket(ServerSocket serverSocket) {
            this.serverSocket = serverSocket;
            return this;
        }

        /**
         * Clears the File Server FileResources database on shut down
         *
         * @param clear Default is false
         * @return builder
         */
        public final FetchFileServer.Builder setClearDatabaseOnShutdown(boolean clear) {
            this.clearDatabaseOnShutdown = clear;
            return this;
        }

        /**
         * Set File Server Logger.
         *
         * @param logger Default. Uses the default logger which is enabled
         * @return builder
         */
        public final FetchFileServer.Builder setLogger(FetchFileServerLogger logger) {
            this.logger = logger;
            return this;
        }

        /**
         * Set authenticator object.
         *
         * @param fetchFileServerAuthenticator Default is null. If Null, the file server will
         * accept all requests.
         * @return builder
         */
        public final FetchFileServer.Builder setAuthenticator(FetchFileServerAuthenticator fetchFileServerAuthenticator) {
            this.fileServerAuthenticator = fetchFileServerAuthenticator;
            return this;
        }

        /**
         * Set Delegate
         *
         * @param fetchFileServerDelegate Default is null. If Null, the file server will
         * attempt to handle custom requests and actions.
         * @return builder
         */
        public final FetchFileServer.Builder setDelegate(FetchFileServerDelegate fetchFileServerDelegate) {
            this.fileServerDelegate = fetchFileServerDelegate;
            return this;
        }

        /**
         * Set Transfer Listener
         *
         * @param fetchTransferListener Default is null.
         * @return builder
         */
        public final FetchFileServer.Builder setTransferListener(FetchTransferListener fetchTransferListener) {
            this.transferListener = fetchTransferListener;
            return this;
        }

        /**
         * Set default Database name the File Server instance will use. This is used to store
         * FileResource information that can later be retrieved by the File Server.
         *
         * @param databaseName Default is LibFetchFileServerDatabaseLib.db
         * @return builder
         */
        public final FetchFileServer.Builder setFileServerDatabaseName(String databaseName) {
            if (!databaseName.isEmpty()) {
                this.fileResourceDatabaseName = databaseName;
            }
            return this;
        }

        /**
         * Sets the progress reporting interval in milliseconds. This controls how often
         * client serving progress is reported. The default value is 2 seconds.
         * This method can only accept values greater than 0.
         *
         * @param progressReportingIntervalMillis Progress reporting interval in milliseconds
         * @return Builder
         * @throws IllegalArgumentException the passed in progress reporting interval is less than 0.
         */
        public final FetchFileServer.Builder setProgressReportingInterval(long progressReportingIntervalMillis) {
            if (progressReportingIntervalMillis < 0L) {
                throw new IllegalArgumentException("progressReportingIntervalMillis cannot be less than 0");
            } else {
                this.progressReportingInMillis = progressReportingIntervalMillis;
                return this;
            }
        }

        /**
         * Set the client persistent connection timeout in milliseconds. The client connection
         * will be closed if inactive at the specified timeout. Default is 1 minute.
         *
         * @param persistentConnectionTimeout Persistent Connection Timeout in milliseconds
         * @return Builder
         * @throws IllegalArgumentException the passed in Persistent Connection Timeout is less than 0.
         */
        public final FetchFileServer.Builder setPersistentConnectionTimeout(long persistentConnectionTimeout) {
            if (persistentConnectionTimeout < 0L) {
                throw new IllegalArgumentException("persistentConnectionTimeout cannot be less than 0");
            } else {
                this.persistentConnectionTimeout = persistentConnectionTimeout;
                return this;
            }
        }

        /**
         * setFileResolver
         *
         * @param fileResolver 1
         * @return 1
         */

        public final FetchFileServer.Builder setFileResolver(FileResolver fileResolver) {
            this.fileResolver = fileResolver;
            return this;
        }

        /**
         * Build the FetchFileServer Instance.
         *
         * @return new Fetch File Server instance.
         */
        public FetchFileServer build() {
            return new FetchFileServerImpl(context, serverSocket, clearDatabaseOnShutdown,
                logger, fileResourceDatabaseName, fileServerAuthenticator,
                fileServerDelegate, transferListener, progressReportingInMillis,
                persistentConnectionTimeout, fileResolver);
        }


        public Builder(Context context) throws IOException {
            this.context = context;
            this.fileResolver = new FileResolver(context.getApplicationContext());
        }
    }
}
